package com.lightboat.common.utils.appSigner;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.Base64;
import java.util.Map;
import java.util.Objects;

import static java.nio.charset.StandardCharsets.UTF_8;

public class JdAppSigner {

    private static final String HEX_CHARACTERS = "0123456789ABCDEF";


    public static String sign(String algorithm, byte[] data, byte[] secret) throws GeneralSecurityException {
        if (Objects.equals(algorithm, "md5-salt")) {
            return bytesToHex(MessageDigest.getInstance("md5").digest(data));
        } else if (Objects.equals(algorithm, "HMacMD5")) {
            Mac mac = Mac.getInstance(algorithm);
            mac.init(new SecretKeySpec(secret, algorithm));
            return Base64.getEncoder().encodeToString(mac.doFinal(data));
        } else if (Objects.equals(algorithm, "HMacSHA1")) {
            Mac mac = Mac.getInstance(algorithm);
            mac.init(new SecretKeySpec(secret, algorithm));
            return Base64.getEncoder().encodeToString(mac.doFinal(data));
        } else if (Objects.equals(algorithm, "HMacSHA256")) {
            Mac mac = Mac.getInstance(algorithm);
            mac.init(new SecretKeySpec(secret, algorithm));
            return Base64.getEncoder().encodeToString(mac.doFinal(data));
        } else if (Objects.equals(algorithm, "HMacSHA512")) {
            Mac mac = Mac.getInstance(algorithm);
            mac.init(new SecretKeySpec(secret, algorithm));
            return Base64.getEncoder().encodeToString(mac.doFinal(data));
        }
        throw new GeneralSecurityException("Algorithm " + algorithm + " not supported yet");
    }

    public static String bytesToHex(byte[] bytes) {
        StringBuilder stringBuilder = new StringBuilder(bytes.length * 2);
        for (byte b : bytes) {
            stringBuilder.append(HEX_CHARACTERS.charAt((b >>> 4) & 0x0F));
            stringBuilder.append(HEX_CHARACTERS.charAt(b & 0x0F));
        }
        return stringBuilder.toString();
    }

    public static String httpBuildQuery(Map<String, String> query) throws UnsupportedEncodingException {
        StringBuilder stringBuilder = new StringBuilder();
        boolean first = true;
        for (Map.Entry<String, String> entry : query.entrySet()) {
            if (!first) {
                stringBuilder.append("&");
            } else {
                first = false;
            }
            stringBuilder.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), UTF_8.name()));
        }
        return stringBuilder.toString();
    }

    public static byte[] readAllBytes(InputStream inputStream) throws IOException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int n;
        while ((n = inputStream.read(buffer)) > 0) {
            outputStream.write(buffer, 0, n);
        }
        return outputStream.toByteArray();
    }
}
